#include "resizeImagenes.h"
#include <math.h>

ofstream logueo ("logueo.txt");
ofstream logueo2 ("logueo2.txt");

int levantoAncho(char * cadena) {
    char buffer[1024] = {};
    int i = 0;

    while (cadena[i] != ' ') {
        buffer[i] = cadena[i];
        i++;
    }
    return atoi(buffer);
}

int levantoAlto(char * cadena) {
    char buffer[1024] = {};
    int i = 0;
    int j = 0;
    int pasamosAncho = 0;

    while (!(pasamosAncho && cadena[i] == ' ')) {
        if (pasamosAncho) {
            buffer[j] = cadena[i];
            j++;
        }
        if (cadena[i] == ' ')
            pasamosAncho = 1;

        i++;
    }
    return atoi(buffer);
}

void convertStringToArrayChar(char * arreglo, string num) {
    for (int i=0;i<(int)num.size();i++)
        arreglo[i] = num[i];
}

/********************************************************************/
/*                        SubMuestreo                               */
/********************************************************************/

void calcularSubMuestreo(FILE * imagen, FILE * imagenNueva, int ancho, int alto, int fr) {
    Foto foto;
    foto.cargarImagen(imagen, ancho, alto);

    float reducir = (100 - (float)fr)/100;
    int nuevoAncho = (int)ceil((float)ancho * reducir);
    int nuevoAlto = (int)ceil((float)alto * reducir);

    logueo << "fr " << fr << endl;
    logueo << "reducir " << reducir << endl;
    logueo << "ancho " << ancho << " alto " << alto << endl;
    logueo << "nuevoAncho " << nuevoAncho << " nuevoAlto " << nuevoAlto << endl;
    logueo << endl;

    Foto fotoNueva(nuevoAncho, nuevoAlto);
    Foto contador(nuevoAncho, nuevoAlto);
    /// Recorro toda la imagen que esta guardada en foto y la ubico en la fotoNueva.
    for (int x=0;x<alto;x++) {
        for (int y=0;y<ancho;y++) {
            int xx = (int)floor((float)x * reducir);
            int yy = (int)floor((float)y * reducir);

            logueo << "x " << x << " y " << y << endl;
            logueo << "xx " << xx << " yy " << yy << endl;
            logueo << "fotoNueva: " << fotoNueva.get(xx, yy) << endl;
            logueo << "foto: " << foto.get(x, y) << endl;

            int acum = fotoNueva.get(xx, yy) + foto.get(x, y);

            logueo << "acum " << acum << endl;
            fotoNueva.set(xx, yy, acum);

            int count = contador.get(xx,yy);
            count++;
            contador.set(xx, yy, count);
            logueo << endl;
        }
    }

    /// Recorro toda la fotoNueva y divido cada posicion por la cantidad de valores que sume,
    /// esta cantidad esta en contador.
    for (int x=0;x<nuevoAlto;x++) {
        for (int y=0;y<nuevoAncho;y++) {
            if (contador.get(x, y) != 0) {
                int valor = fotoNueva.get(x, y) / contador.get(x, y);
                fotoNueva.set(x, y, valor);
            }
        }
    }

    /// Guardamos la fotoNueva en la imagenNueva
    for (int x=0;x<nuevoAlto;x++) {
        for (int y=0;y<nuevoAncho;y++) {
            fputc(fotoNueva.get(x, y), imagenNueva);
        }
    }

}

void subMuestreoAux(FILE * imagen, FILE * imagenNueva, int fr) {
    char basura [100];
    int ancho;
    int alto;

    /// Guardo la posicion donde comienza la imagen.
    fpos_t current_position;
    fgetpos (imagen, &current_position);

    /// Guardo la posicion donde comienza la imagenNueva.
    fpos_t current_position_nueva;
    fgetpos (imagenNueva, &current_position_nueva);

    /// Levantamos de la imagen original.
    fgets(basura, 100, imagen);
    cout << "Indentifying file: " << basura;

    /// Guardamos el identifying file en la imagen nueva.
    fputs(basura, imagenNueva);

    /// Levantamos el comentario de la imagen original # Created by Paint Shop Pro 5.
    fgets(basura, 100, imagen);
    cout << "Comentario: " << basura;

    /// Guardamos el comentario en la imagen nueva.
    fputs(basura, imagenNueva);

    /// Levantamos el ancho.
    fgets(basura, 100, imagen);
    ancho = levantoAncho(basura);
    cout << "Width: " << ancho << endl;

    /// Levantamos el alto.
    alto = levantoAlto(basura);
    cout << "Height: " << alto << endl;

    /// Creamos el alto y ancho para guardar en la imagen nueva.
    float reducir = (100 - (float)fr)/100;
    int nuevoAncho = (int)ceil((float)ancho * reducir);
    int nuevoAlto = (int)ceil((float)alto * reducir);
    stringstream ss;
    ss << nuevoAncho << " " << nuevoAlto << "\n";
    char anchoyalto[100] = {};
    convertStringToArrayChar(anchoyalto, ss.str());

    /// Guardamos el ancho y el alto en la imagen nueva.
    fputs(anchoyalto,imagenNueva);

    /// Levantamos el valor maximo de gris.
    fgets(basura, 5,imagen);
    cout << "Maximum grayscale value: " << basura << endl;

    /// TODO Tendriamos que obtener el valor maximo de gris de la imagen generada.

    /// Guardamos el valor maximo de gris en la imagen nueva.
    fputs(basura,imagenNueva);

    /// Reducimos la imagen.
    calcularSubMuestreo(imagen,imagenNueva, ancho, alto, fr);

    /// Restauro la posicion de la imagen.
    fseek(imagen, current_position.__pos, SEEK_SET);

    /// Restauro la posicion de la imagenNueva.
    fseek(imagenNueva, current_position_nueva.__pos, SEEK_SET);
}

int subMuestreo(FILE * imagen, int fr) {
    char fileName[] = "./salidaSubMuestreo.pgm";
    FILE * imagenNueva;
    imagenNueva = fopen(fileName, "w+");

    if (imagenNueva == NULL)
        perror ("Error abriendo el archivo para subMuestreo");
    else
    {
        cout << "Creamos el archivo: " << fileName << endl;
        cout << "Factor reduccion: " << fr << endl;

        subMuestreoAux(imagen, imagenNueva, fr);

        fclose(imagenNueva);
    }

    return 0;
}

/********************************************************************/
/*                        SobreMuestreo                             */
/********************************************************************/

void calcularSobreMuestreo(FILE * imagen, FILE * imagenNueva, int ancho, int alto, int fr) {
    Foto foto;
    foto.cargarImagen(imagen, ancho, alto);

    float reducir = (100 - (float)fr)/100;
    float aumentar = 100/(100 - (float)fr);
    int nuevoAncho = (int)ceil((float)ancho * aumentar);
    int nuevoAlto = (int)ceil((float)alto * aumentar);

    logueo2 << "fr " << fr << endl;
    logueo2 << "aumentar " << aumentar << endl;
    logueo2 << "ancho " << ancho << " alto " << alto << endl;
    logueo2 << "nuevoAncho " << nuevoAncho << " nuevoAlto " << nuevoAlto << endl;
    logueo2 << endl;

    Foto fotoNueva(nuevoAncho, nuevoAlto);

    /// Recorro toda la imagen que esta guardada en foto y la ubico en la fotoNueva.
    for (int x=0;x<nuevoAlto;x++) {
        for (int y=0;y<nuevoAncho;y++) {
            int xx = (int)floor((float)x * reducir);
            int yy = (int)floor((float)y * reducir);

            logueo2 << "x " << x << " y " << y << endl;
            logueo2 << "xx " << xx << " yy " << yy << endl;
            logueo2 << "foto: " << foto.get(xx, yy) << endl;

            int valor =  foto.get(xx, yy);
            fotoNueva.set(x, y, valor);

            logueo2 << endl;
        }
    }

    /// Guardamos la fotoNueva en la imagenNueva
    for (int x=0;x<nuevoAlto;x++) {
        for (int y=0;y<nuevoAncho;y++) {
            fputc(fotoNueva.get(x, y), imagenNueva);
        }
    }

}

void sobreMuestreoAux(FILE * imagen, FILE * imagenNueva, int fr) {
    char basura [100];
    int ancho;
    int alto;

    /// Guardo la posicion donde comienza la imagen.
    fpos_t current_position;
    fgetpos (imagen, &current_position);

    /// Guardo la posicion donde comienza la imagenNueva.
    fpos_t current_position_nueva;
    fgetpos (imagenNueva, &current_position_nueva);

    /// Levantamos de la imagen original.
    fgets(basura, 100, imagen);
    cout << "Indentifying file: " << basura;

    /// Guardamos el identifying file en la imagen nueva.
    fputs(basura, imagenNueva);

    /// Levantamos el comentario de la imagen original # Created by Paint Shop Pro 5.
    fgets(basura, 100, imagen);
    cout << "Comentario: " << basura;

    /// Guardamos el comentario en la imagen nueva.
    fputs(basura, imagenNueva);

    /// Levantamos el ancho.
    fgets(basura, 100, imagen);
    ancho = levantoAncho(basura);
    cout << "Width: " << ancho << endl;

    /// Levantamos el alto.
    alto = levantoAlto(basura);
    cout << "Height: " << alto << endl;

    /// Creamos el alto y ancho para guardar en la imagen nueva.
    float aumentar = 100/(100 - (float)fr);
    int nuevoAncho = (int)ceil((float)ancho * aumentar);
    int nuevoAlto = (int)ceil((float)alto * aumentar);
    stringstream ss;
    ss << nuevoAncho << " " << nuevoAlto << "\n";
    char anchoyalto[100] = {};
    convertStringToArrayChar(anchoyalto, ss.str());

    /// Guardamos el ancho y el alto en la imagen nueva.
    fputs(anchoyalto,imagenNueva);

    /// Levantamos el valor maximo de gris.
    fgets(basura, 5,imagen);
    cout << "Maximum grayscale value: " << basura << endl;

    /// TODO Tendriamos que obtener el valor maximo de gris de la imagen generada.

    /// Guardamos el valor maximo de gris en la imagen nueva.
    fputs(basura,imagenNueva);

    /// Reducimos la imagen.
    calcularSobreMuestreo(imagen,imagenNueva, ancho, alto, fr);

    /// Restauro la posicion de la imagen.
    fseek(imagen, current_position.__pos, SEEK_SET);

    /// Restauro la posicion de la imagenNueva.
    fseek(imagenNueva, current_position_nueva.__pos, SEEK_SET);
}

int sobreMuestreo(FILE * imagen, int fr) {
    char fileName[] = "./salidaSobreMuestreo.pgm";
    FILE * imagenNueva;
    imagenNueva = fopen(fileName, "w+");

    if (imagenNueva == NULL)
        perror ("Error abriendo el archivo para sobreMuestreo");
    else
    {
        cout << "Creamos el archivo: " << fileName << endl;
        cout << "Factor reduccion: " << fr << endl;

        sobreMuestreoAux(imagen, imagenNueva, fr);

        fclose(imagenNueva);
    }
    return 0;
}
